using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Drawing.Imaging;

namespace ESTPrototype
{
    public partial class ESTMCanvas : UserControl
    {
        private enum Axis { X = 1, Y = 2 };
        private static int CenterInParent(Control pControl, Axis pAxis)
        {
            if ((pAxis & Axis.X) != 0)
            {
                return pControl.Parent.Width / 2 - pControl.Width / 2;
            }

            return pControl.Parent.Height / 2 - pControl.Height / 2;
        }

        public ESTMCanvas()
        {
            InitializeComponent();

            this.ThumbnailSize = new Size(102, 98);

            this.mLinearModeImage = new Bitmap(this.pictureBox1.Width, this.pictureBox1.Height);

            this.mAnimationTimer = new System.Threading.Timer(this.cAnimationTimerTick, null, Timeout.Infinite, 10);
            this.mAnimationStopwatch = new System.Diagnostics.Stopwatch();

            this.mAnimationDuration = 500.0f;

            {
                // a sixty percent semitransparent color matrix
                ColorMatrix colorMatrix = new ColorMatrix(new float[5][] {
                    new float[5]{1.0f, 0.0f, 0.0f, 0.0f, 0.0f},
                    new float[5]{0.0f, 1.0f, 0.0f, 0.0f, 0.0f},
                    new float[5]{0.0f, 0.0f, 1.0f, 0.0f, 0.0f},
                    new float[5]{0.0f, 0.0f, 0.0f, 0.3f, 0.0f},
                    new float[5]{0.0f, 0.0f, 0.0f, 0.0f, 1.0f} });

                this.mImageOfDraggingThumbnail = new Bitmap(this.mThumbnailSize.Width, this.mThumbnailSize.Height);
                this.mRectangleForSemiTransparentThumbnail = new Rectangle(Point.Empty, this.mThumbnailSize);

                // initialize the image attributes
//                this.mSemiTransparentImageAttributes = new ImageAttributes();
//                this.mSemiTransparentImageAttributes.SetColorMatrix(colorMatrix);
            }

            this.SizeChanged += new EventHandler(this.cSizeChanged);

            this.transitionPanel1.MouseMove += new MouseEventHandler(transitionPanel1_MouseMove);

            this.button1_Click(this, EventArgs.Empty);
        }

        public Size ThumbnailSize
        {
            get
            {
                return this.mThumbnailSize;
            }

            set
            {
                this.mThumbnailSize = value;
            }
        }

        private void transitionPanel1_MouseMove(object sender, MouseEventArgs e)
        {
            //Random random = new Random();
            //this.transitionPanel1.BackColor = Color.FromArgb(random.Next(1, 255), random.Next(1, 255), random.Next(1, 255));
        }

        public void AddScreenThumbnail(Thumbnail pScreenThumbnail)
        {
            // if a thumbnail gets added to this control it first goes to the unlinked screens flowlayout
            this.AddScreenThumbnailToFlowLayout(pScreenThumbnail);
        }


        //private Control mThumbnailBeingDraggedFromFlowLayout;

        private void cMouseDownOnThumbnailInFlowLayout(object pSender, MouseEventArgs pEventArgs)
        {
            // set this control to our member that represents the thumbnail that is being dragged out of the flowlayout
            //this.mThumbnailBeingDraggedFromFlowLayout = pSender as Control;

            Bitmap b = new Bitmap(this.mThumbnailSize.Width, this.mThumbnailSize.Height);
            ((Control)pSender).DrawToBitmap(b, new Rectangle(0, 0, 102, 98));

            this.transitionPanel1.SemiTransparentImageOfScreenThumbnail = b;

        }

        private void AddScreenThumbnailToFlowLayout(Thumbnail pScreenThumbnail)
        {
            // add some callbacks to this thumbnail
            pScreenThumbnail.MouseDown += new MouseEventHandler(this.cMouseDownOnThumbnailInFlowLayout);
            pScreenThumbnail.MouseUp += new MouseEventHandler(this.cMouseUpOnThumbnailInFlowLayout);
            pScreenThumbnail.MouseMove += new MouseEventHandler(this.cMouseMoveOnThumbnailInFlowLayout);

            // finally add this thumbnail to the flowlayout panel that represents unlinked screens
            this.flowLayoutPanel1.Controls.Add(pScreenThumbnail);
        }

        private void RemoveScreenThumbnailFromFlowLayout(Thumbnail pScreenThumbnail)
        {
            // make sure this thumbnail exists in the flowlayout
            if (!this.flowLayoutPanel1.Controls.Contains(pScreenThumbnail))
            {
                return;
            }

            // this thumbnail definetly exists in the flowlayout so proceed to remove it
            
            // remove our callbacks from this control
            pScreenThumbnail.MouseDown -= this.cMouseDownOnThumbnailInFlowLayout;
            pScreenThumbnail.MouseUp -= this.cMouseUpOnThumbnailInFlowLayout;
            pScreenThumbnail.MouseMove -= this.cMouseMoveOnThumbnailInFlowLayout;

            // and finally remove it
            this.flowLayoutPanel1.Controls.Remove(pScreenThumbnail);
        }

        private void cMouseUpOnThumbnailInFlowLayout(object pSender, MouseEventArgs pEventArgs)
        {
            // reset our member that represents the thumbnail that is being dragged out of the flowlayout
            //this.mThumbnailBeingDraggedFromFlowLayout = null;

            //this.mImageOfDraggingThumbnail = null;

            // check if we let go inside of the transition panel
            if (this.transitionPanel1.DrawSemiTransparentScreenThumbnail)
            {
                Thumbnail screenThumbnail = (Thumbnail)pSender;

                // first remove it from the flow layout
                this.RemoveScreenThumbnailFromFlowLayout(screenThumbnail);

                // add this thumbnail to the transition panel
                this.transitionPanel1.AddScreenThumbnail(screenThumbnail);

                //this.transitionPanel1.Controls.Add((Control)pSender);
                

                this.transitionPanel1.DrawSemiTransparentScreenThumbnail = false;
            }
        }

        bool mDrawSemiTransparentThumbnail;

        private void cMouseMoveOnThumbnailInFlowLayout(object pSender, MouseEventArgs pEventArgs)
        {
            Thumbnail thumbnail = pSender as Thumbnail;

            thumbnail.Label.Text = pEventArgs.X.ToString() + ", " + pEventArgs.Y.ToString();

            if (this.mImageOfDraggingThumbnail != null)
            {
                Point mousePosition = new Point(
                                            (this.flowLayoutPanel1.Left + thumbnail.Left + pEventArgs.X),
                                            (this.flowLayoutPanel1.Top + thumbnail.Top + pEventArgs.Y));

                if (mousePosition.Y < this.transitionPanel1.Height)
                {
                    //this.mRectangleForSemiTransparentThumbnail.Location = new Point(mousePosition.X - this.mThumbnailSize.Width / 2, mousePosition.Y - this.mThumbnailSize.Height / 2);

                    this.transitionPanel1.MousePositionForSemiTransparentScreenThumbnail = mousePosition;
                    this.transitionPanel1.DrawSemiTransparentScreenThumbnail = true;

                    //this.mDrawSemiTransparentThumbnail = true;

                    //this.mRectangleForSemiTransparentThumbnail.Location.Offset(this.mThumbnailSize.Width / 2, this.mThumbnailSize.Height / 2);// = new Point(mousePosition.X - 102 / 2, mousePosition.Y - 98 / 2);


                    //Rectangle destRect = new Rectangle(mousePosition, new Size(102, 98));
                    //destRect.Offset(-102 / 2, -98 / 2);

                    this.transitionPanel1.Invalidate();
                    //this.Invalidate(this.mRectangleForSemiTransparentThumbnail);

                    //this.transitionPanel1.Invalidate(this.mRectangleForSemiTransparentThumbnail);

                    /*                    using (Graphics graphics = this.transitionPanel1.CreateGraphics())
                                        {
                        
                                            graphics.SetClip(this.mRectangleForSemiTransparentThumbnail);
                                            graphics.Clear(Color.White);
                                            graphics.DrawImage(this.mImageOfDraggingThumbnail, this.mRectangleForSemiTransparentThumbnail, 0, 0, 102, 98, GraphicsUnit.Pixel, this.mSemiTransparentImageAttributes);
                                        }
                     */
                }

                else
                {
                    this.transitionPanel1.DrawSemiTransparentScreenThumbnail = false;
                }
            }
        }

        private Rectangle mRectangleForSemiTransparentThumbnail;
        private Bitmap mImageOfDraggingThumbnail;

        private void cSizeChanged(object pSender, EventArgs pEventArgs)
        {
            if (this.mAnimationStopwatch.IsRunning)
            {
                if (this.mLinearMode)
                {
                    this.mDestPointForToggleButton = new Point(this.Width - this.button1.Width - 8, this.label1.Location.Y + 2);
                }

                else
                {
                    this.mDestPointForToggleButton = new Point(CenterInParent(this.button1, Axis.X), this.pictureBox1.Top + this.pictureBox1.Height + 10);
                }

                this.StopAnimation();
            }
        }

        private void cAnimationTimerTick(object pSender)
        {
            if (!this.mAnimationStopwatch.IsRunning)
            {
                return;
            }

            if (this.InvokeRequired)
            {
                this.Invoke(new System.Threading.TimerCallback(this.cAnimationTimerTick),
                    new object[] { pSender });
            }

            else
            {
                bool stopAnimation = false;

                float timeDifference = this.mAnimationStopwatch.ElapsedMilliseconds / this.mAnimationDuration;
                int x = (int)(this.mSourcePointForToggleButton.X + this.mHorizontalDifference * timeDifference);
                int y = (int)(this.mSourcePointForToggleButton.Y + this.mVerticalDifference * timeDifference);

                if (this.mHorizontalDifference < 0)
                {
                    if (x <= this.mDestPointForToggleButton.X)
                    {
                        stopAnimation = true;
                    }
                }

                else
                {
                    if (x >= this.mDestPointForToggleButton.X)
                    {
                        stopAnimation = true;
                    }
                }

                if (this.mVerticalDifference < 0)
                {
                    if (y <= this.mDestPointForToggleButton.Y)
                    {
                        stopAnimation = true;
                    }
                }

                else
                {
                    if (y >= this.mDestPointForToggleButton.Y)
                    {
                        stopAnimation = true;
                    }
                }

                if (stopAnimation)
                {
                    this.StopAnimation();
                }

                else
                {
                    this.button1.Location = new Point(x, y);
                }
            }
        }

        private void StopAnimation()
        {
            // turn off the animation timer
            this.mAnimationTimer.Change(Timeout.Infinite, Timeout.Infinite);
            
            // turn off the animation stop watch
            this.mAnimationStopwatch.Stop();
            this.mAnimationStopwatch.Reset();

            // enable the button
            this.button1.Enabled = true;

            // toggle the modes
            this.mLinearMode = !this.mLinearMode;

            if (!this.mLinearMode)
            {
                this.transitionPanel1.Enabled = true;
                this.label1.Enabled = true;
                this.flowLayoutPanel1.Enabled = true;

                Control control;
                for (int i = this.flowLayoutPanel1.Controls.Count - 1; i >= 0; i--)
                {
                    control = this.flowLayoutPanel1.Controls[i];
                    if (control.Tag is Point)
                    {
                        this.transitionPanel1.Controls.Add(control);
                        control.Location = (Point)control.Tag;
                    }
                }
            }

            // finally set the location on the button to the destination location
            this.button1.Location = this.mDestPointForToggleButton;

            // throw the focus to the label
            this.label1.Focus();
        }
        
        private void button1_Click(object sender, EventArgs e)
        {
            // disable the button immediatley
            this.button1.Enabled = false;

            if (this.mLinearMode)
            {
                this.button1.Text = "Use Linear Transitions";
                this.button1.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;

                this.mDestPointForToggleButton = new Point(this.Width - this.button1.Width - 8, this.label1.Location.Y + 2);//100);//this.Height - this.dockContainer1.Height);

                this.pictureBox1.Visible = false;
                this.transitionPanel1.Visible = true;
                this.transitionPanel1.Enabled = false;
                this.panel2.Visible = true;
                this.label1.Visible = true;
                this.label1.Enabled = false;
                this.flowLayoutPanel1.Visible = true;
                this.flowLayoutPanel1.Enabled = false;
            }

            else
            {
                this.button1.Text = "Add Custom Transitions";
                this.button1.Anchor = AnchorStyles.Top;

                this.mDestPointForToggleButton = new Point(CenterInParent(this.button1, Axis.X), this.pictureBox1.Top + this.pictureBox1.Height + 10);

                this.pictureBox1.Visible = true;
                this.transitionPanel1.Visible = false;
                this.panel2.Visible = false;
                this.label1.Visible = false;
                this.flowLayoutPanel1.Visible = false;
            }

            if (this.mUseAnimation)
            {
                this.mSourcePointForToggleButton = this.button1.Location;

                this.mHorizontalDifference = this.mDestPointForToggleButton.X - this.mSourcePointForToggleButton.X;
                this.mVerticalDifference = this.mDestPointForToggleButton.Y - this.mSourcePointForToggleButton.Y;

                this.mAnimationTimer.Change(0, 100);
                this.mAnimationStopwatch.Start();
            }

            else
            {
                this.StopAnimation();
                this.mUseAnimation = true;
            }
        }

        private Size mThumbnailSize;

        //private System.Diagnostics.Stopwatch mAnimationTimer;
        private System.Threading.Timer mAnimationTimer;
        private System.Diagnostics.Stopwatch mAnimationStopwatch;
        private float mAnimationDuration;
        private bool mUseAnimation;

        private Point mSourcePointForToggleButton;
        private Point mDestPointForToggleButton;

        private int mHorizontalDifference;
        private int mVerticalDifference;

        private bool mLinearMode;

        private Image mLinearModeImage;

        
    }
}
